bitkeeper revision 1.1159.79.2 (414c1134FG1zvS9xwv2yPDvyS7W3ig)
authorkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Sat, 18 Sep 2004 10:43:00 +0000 (10:43 +0000)
committerkaf24@freefall.cl.cam.ac.uk <kaf24@freefall.cl.cam.ac.uk>
Sat, 18 Sep 2004 10:43:00 +0000 (10:43 +0000)
Linux scrubs memory before returnign it to Xen, or transferring it to
other domains (e.g., net backend driver). To avoid continual scrubbing during
network transfers, I allocate rx skbuffs from a dedicated slab cache. Pages
only neded to be scrubbed on entry to the cache, which should be ratehr more
occasional than allocs/frees.
Finally, scrubbing can be entirely disabled via a config option under the
'XEN' menu in the 2.4 and 2.6 kernel configurators.

21 files changed:
.rootkeys
linux-2.4.27-xen-sparse/arch/xen/config.in
linux-2.4.27-xen-sparse/arch/xen/defconfig-xen0
linux-2.4.27-xen-sparse/arch/xen/defconfig-xenU
linux-2.4.27-xen-sparse/arch/xen/drivers/balloon/balloon.c
linux-2.4.27-xen-sparse/arch/xen/kernel/Makefile
linux-2.4.27-xen-sparse/include/asm-xen/page.h
linux-2.4.27-xen-sparse/include/linux/skbuff.h
linux-2.4.27-xen-sparse/mkbuildtree
linux-2.6.8.1-xen-sparse/arch/xen/Kconfig
linux-2.6.8.1-xen-sparse/arch/xen/configs/xen0_defconfig
linux-2.6.8.1-xen-sparse/arch/xen/configs/xenU_defconfig
linux-2.6.8.1-xen-sparse/arch/xen/i386/kernel/pci-dma.c
linux-2.6.8.1-xen-sparse/arch/xen/i386/mm/hypervisor.c
linux-2.6.8.1-xen-sparse/arch/xen/kernel/Makefile
linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c [new file with mode: 0644]
linux-2.6.8.1-xen-sparse/drivers/xen/netback/netback.c
linux-2.6.8.1-xen-sparse/drivers/xen/netfront/netfront.c
linux-2.6.8.1-xen-sparse/include/asm-xen/asm-i386/page.h
linux-2.6.8.1-xen-sparse/include/linux/skbuff.h
xen/common/page_alloc.c

index 045d64edb33f05a3455964fbbb6b0cd5f0555837..640b527505370ad066bcfa75dc15c74b44d840d9 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 412dfae9eA3_6e6bCGUtg1mj8b56fQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/gnttab.c
 40f56239sFcjHiIRmnObRIDF-zaeKQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/process.c
 40f562392LBhwmOxVPsYdkYXMxI_ZQ linux-2.6.8.1-xen-sparse/arch/xen/kernel/reboot.c
+414c113396tK1HTVeUalm3u-1DF16g linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c
 3f68905c5eiA-lBMQSvXLMWS1ikDEA linux-2.6.8.1-xen-sparse/arch/xen/kernel/xen_proc.c
 41261688yS8eAyy-7kzG4KBs0xbYCA linux-2.6.8.1-xen-sparse/drivers/Makefile
 4108f5c1WfTIrs0HZFeV39sttekCTw linux-2.6.8.1-xen-sparse/drivers/char/mem.c
index 8fa004a16b0f933be587832accc138044cbdb09b..d6a3936547ec717aa76b1e4bcf83924a02b1f0e7 100644 (file)
@@ -16,6 +16,7 @@ mainmenu_option next_comment
 comment 'Xen'
 bool 'Support for privileged operations (domain 0)' CONFIG_XEN_PRIVILEGED_GUEST
 bool 'Device-driver domain (physical device access)' CONFIG_XEN_PHYSDEV_ACCESS
+bool 'Scrub memory before freeing it to Xen' CONFIG_XEN_SCRUB_PAGES
 endmenu
 # The IBM S/390 patch needs this.
 define_bool CONFIG_NO_IDLE_HZ y
index 1f0dcfc70d3480616a970fadb272f4900c7782b3..21b0a99eab053964c9fe2ef5ad2b37f6fccb9935 100644 (file)
@@ -12,6 +12,7 @@ CONFIG_UID16=y
 #
 CONFIG_XEN_PRIVILEGED_GUEST=y
 CONFIG_XEN_PHYSDEV_ACCESS=y
+CONFIG_XEN_SCRUB_PAGES=y
 CONFIG_NO_IDLE_HZ=y
 CONFIG_FOREIGN_PAGES=y
 
index e31d05679ed96d47351fe6dde84a036d45c45fd6..a975cc9f9f3f4e32b621255927086a5288321919 100644 (file)
@@ -12,6 +12,7 @@ CONFIG_UID16=y
 #
 # CONFIG_XEN_PRIVILEGED_GUEST is not set
 # CONFIG_XEN_PHYSDEV_ACCESS is not set
+CONFIG_XEN_SCRUB_PAGES=y
 CONFIG_NO_IDLE_HZ=y
 # CONFIG_FOREIGN_PAGES is not set
 CONFIG_NETDEVICES=y
index b13e3d75efaafba6fbc1fb99fd8ecaed25792af9..c1a22a21f203c1f78cced7b21655e02d987015a1 100644 (file)
@@ -104,8 +104,20 @@ static unsigned long inflate_balloon(unsigned long num_pages)
     {
        unsigned long mfn = phys_to_machine_mapping[*currp];
         curraddr = (unsigned long)page_address(mem_map + *currp);
+        /* Blow away page contents for security, and also p.t. ref if any. */
        if ( curraddr != 0 )
+        {
+            scrub_pages(curraddr, 1);
             queue_l1_entry_update(get_ptep(curraddr), 0);
+        }
+#ifdef CONFIG_XEN_SCRUB_PAGES
+        else
+        {
+            void *p = kmap(&mem_map[*currp]);
+            scrub_pages(p, 1);
+            kunmap(&mem_map[*currp]);
+        }
+#endif
         phys_to_machine_mapping[*currp] = DEAD;
         *currp = mfn;
     }
@@ -388,9 +400,9 @@ static int balloon_write(struct file *file, const char *buffer,
     }
 
     len = strnlen_user(buffer, count);
-    if (len==0) return -EBADMSG;
-    if (len==1) return 1; /* input starts with a NUL char */
-    if ( strncpy_from_user(memstring, buffer, len) < 0)
+    if ( len == 0 ) return -EBADMSG;
+    if ( len == 1 ) return 1; /* input starts with a NUL char */
+    if ( strncpy_from_user(memstring, buffer, len) < 0 )
         return -EFAULT;
 
     endchar = memstring;
index 3ad868e3579640b6179185e5a034a5ec06f4a922..30488e666b012f150ade26cff29185aab9597bd2 100644 (file)
@@ -6,12 +6,12 @@ all: kernel.o head.o init_task.o
 
 O_TARGET := kernel.o
 
-export-objs     := i386_ksyms.o gnttab.o
+export-objs     := i386_ksyms.o gnttab.o skbuff.o
 
 obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o  \
                ptrace.o ioport.o ldt.o setup.o time.o sys_i386.o \
                i386_ksyms.o i387.o evtchn.o ctrl_if.o pci-dma.o \
-               reboot.o fixup.o gnttab.o
+               reboot.o fixup.o gnttab.o skbuff.o
 
 ifdef CONFIG_PCI
 obj-y  += pci-i386.o pci-pc.o
index 6826f65cc022365b7adce80198b721e1f4680351..26e504485bf0593f8ff7ae09680ec077debbfaa5 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <linux/config.h>
+#include <linux/string.h>
 #include <asm/types.h>
 #include <asm/hypervisor-ifs/hypervisor-if.h>
 
+#ifdef CONFIG_XEN_SCRUB_PAGES
+#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
+#else
+#define scrub_pages(_p,_n) ((void)0)
+#endif
+
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
index 9698aa216c7968778a3f2c749b63e74835faf427..009c29bcf6da3db5b7509f2e3e13c25fb8fb241b 100644 (file)
@@ -1027,19 +1027,18 @@ static inline void __skb_queue_purge(struct sk_buff_head *list)
  *
  *     %NULL is returned in there is no free memory.
  */
+#ifndef CONFIG_XEN 
 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
                                              int gfp_mask)
 {
-       struct sk_buff *skb;
-#if defined(CONFIG_XEN)
-       length = (PAGE_SIZE/2)+1; /* force slab allocater to give us a page */
-#endif
-       skb = alloc_skb(length+16, gfp_mask);
+       struct sk_buff *skb = alloc_skb(length+16, gfp_mask);
        if (skb)
                skb_reserve(skb,16);
        return skb;
 }
+#else
+extern struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask);
+#endif
 
 /**
  *     dev_alloc_skb - allocate an skbuff for sending
index decd9037d5a37657fc3866d89681c493179152c0..300b15cb73fb7ed52ee2bbd7a3baa2b6c0e07525 100755 (executable)
@@ -228,6 +228,7 @@ ln -sf ../../../${LINUX_26}/arch/xen/kernel/evtchn.c
 ln -sf ../../../${LINUX_26}/arch/xen/kernel/fixup.c
 ln -sf ../../../${LINUX_26}/arch/xen/kernel/gnttab.c
 ln -sf ../../../${LINUX_26}/arch/xen/kernel/reboot.c
+ln -sf ../../../${LINUX_26}/arch/xen/kernel/skbuff.c
 ln -sf ../../../${LINUX_26}/arch/xen/i386/kernel/ioport.c
 ln -sf ../../../${LINUX_26}/arch/xen/i386/kernel/pci-dma.c
 
index a7e3994e1033fdb6155cd070179463c995b0c5a8..57e3ebaf95ecf4e3119a7e4e2777aad9602bd8ec 100644 (file)
@@ -100,16 +100,26 @@ config XEN_WRITABLE_PAGETABLES
        help
          Use writable L1 pagetables
 
+config XEN_SCRUB_PAGES
+        bool "Scrub memory before freeing it to Xen"
+        default y
+        help
+          Erase memory contents before freeing it back to Xen's global
+          pool. This ensures that any secrets contained within that
+          memory (e.g., private keys) cannot be found by other guests that
+          may be running on the machine. Most people will want to say Y here.
+          If security is not a concern then you may increase performance by
+          saying N.
+
 endmenu
 
 config FOREIGN_PAGES
        bool
        default y
 
-config PAGESIZED_SKBS
+config HAVE_ARCH_DEV_ALLOC_SKB
        bool
-       default y if XEN_NETDEV_BACKEND
-       default n if !XEN_NETDEV_BACKEND
+       default y
 
 #config VT
 #      bool
index a118d649ccbe91c4ce9d6c30939ba5e43fc759e0..42aeb485be1fec409670a43f7ac1f68f81eb6fc3 100644 (file)
@@ -16,8 +16,9 @@ CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 # CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_WRITABLE_PAGETABLES=y
+CONFIG_XEN_SCRUB_PAGES=y
 CONFIG_FOREIGN_PAGES=y
-CONFIG_PAGESIZED_SKBS=y
+CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
 CONFIG_X86=y
 # CONFIG_X86_64 is not set
 
index a3efc64d583aef073a037175d5e77badfd29637f..d6940f6fecc282d5799365b526b2086b6970b576 100644 (file)
@@ -16,8 +16,9 @@ CONFIG_XEN_BLKDEV_FRONTEND=y
 CONFIG_XEN_NETDEV_FRONTEND=y
 # CONFIG_XEN_NETDEV_FRONTEND_PIPELINED_TRANSMITTER is not set
 CONFIG_XEN_WRITABLE_PAGETABLES=y
+CONFIG_XEN_SCRUB_PAGES=y
 CONFIG_FOREIGN_PAGES=y
-# CONFIG_PAGESIZED_SKBS is not set
+CONFIG_HAVE_ARCH_DEV_ALLOC_SKB=y
 CONFIG_X86=y
 # CONFIG_X86_64 is not set
 
index 6135d057b2de0f572f9abe7451fa36dc95d0c0f3..cc9bd03e12ccc028fb95c5f96fddb5c5b0791339 100644 (file)
@@ -55,6 +55,7 @@ void *dma_alloc_coherent(struct device *dev, size_t size,
                pmd_t         *pmd;
                pte_t         *pte;
                unsigned long  pfn, i;
+               scrub_pages(vstart, 1 << order);
                /* 1. Zap current PTEs, giving away the underlying pages. */
                for (i = 0; i < (1<<order); i++) {
                        pgd = pgd_offset_k(   (vstart + (i*PAGE_SIZE)));
index a57eabcd8c5dd6f037e1cc7f55fc238a8ae09cd3..c5f9b07224301e2aaf4c3e7cb5d98245bc261713 100644 (file)
@@ -414,6 +414,8 @@ unsigned long allocate_empty_lowmem_region(unsigned long pages)
     if ( vstart == 0 )
         return 0UL;
 
+    scrub_pages(vstart, 1 << order);
+
     pfn_array = vmalloc((1<<order) * sizeof(*pfn_array));
     if ( pfn_array == NULL )
         BUG();
index 3c9542d659f3105f87b14580c432253e31f522b8..38fabf7412ec116d6f7fd236339fedd6e1e235ae 100644 (file)
@@ -10,4 +10,4 @@ $(obj)/vmlinux.lds.s:
 extra-y += vmlinux.lds.s
 
 obj-y  := ctrl_if.o evtchn.o fixup.o process.o reboot.o xen_proc.o empty.o \
-           gnttab.o
+           gnttab.o skbuff.o
diff --git a/linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c b/linux-2.6.8.1-xen-sparse/arch/xen/kernel/skbuff.c
new file mode 100644 (file)
index 0000000..0c24694
--- /dev/null
@@ -0,0 +1,68 @@
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <asm/io.h>
+#include <asm/page.h>
+
+EXPORT_SYMBOL(__dev_alloc_skb);
+
+static kmem_cache_t *skbuff_cachep;
+
+struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask)
+{
+    struct sk_buff *skb;
+    u8             *new_data, *new_shinfo; 
+
+    /*
+     * Yuk! There is no way to get a skbuff head without allocating the
+     * data area using kmalloc(). So we do that and then replace the default
+     * data area with our own.
+     */
+    skb = alloc_skb(0, gfp_mask);
+    if ( unlikely(skb == NULL) )
+        return NULL;
+
+    new_data = kmem_cache_alloc(skbuff_cachep, gfp_mask);
+    if ( new_data == NULL )
+    {
+        dev_kfree_skb(skb);
+        return NULL;
+    }
+
+    new_shinfo = 
+        new_data + PAGE_SIZE - sizeof(struct skb_shared_info);
+    memcpy(new_shinfo, skb_shinfo(skb), sizeof(struct skb_shared_info));
+
+    kfree(skb->head);
+
+    skb->head = new_data;
+    skb->data = skb->tail = new_data + 16; /* __dev_alloc_skb does this */
+    skb->end  = new_shinfo;
+    skb->truesize = 1500;                  /* is this important? */
+
+    return skb;
+}
+
+static void skbuff_ctor(void *buf, kmem_cache_t *cachep, unsigned long unused)
+{
+    scrub_pages(buf, 1);
+}
+
+static int __init skbuff_init(void)
+{
+    skbuff_cachep = kmem_cache_create(
+        "xen-skb", PAGE_SIZE, PAGE_SIZE, 0, skbuff_ctor, NULL);
+    return 0;
+}
+__initcall(skbuff_init);
index 296771b83774252474a0dca216bbc22d2d43e3d1..242f5007808634bebb23852ee8d519c21af07818 100644 (file)
@@ -132,7 +132,7 @@ int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
          (((unsigned long)skb->end ^ (unsigned long)skb->head) & PAGE_MASK) ||
          ((skb->end - skb->head) < (PAGE_SIZE/2)) )
     {
-        struct sk_buff *nskb = alloc_skb(PAGE_SIZE-1024, GFP_ATOMIC);
+        struct sk_buff *nskb = dev_alloc_skb(PAGE_SIZE);
         int hlen = skb->data - skb->head;
         if ( unlikely(nskb == NULL) )
             goto drop;
index 683dd616da43620ed4098754a907825628512734..f04c6a1b59913850cd9593caac367a4b019306c7 100644 (file)
@@ -39,6 +39,7 @@
 #ifndef __GFP_NOWARN
 #define __GFP_NOWARN 0
 #endif
+#define alloc_skb_page() __dev_alloc_skb(PAGE_SIZE, GFP_ATOMIC|__GFP_NOWARN)
 
 /*
  * If the backend driver is pipelining transmit requests then we can be very
@@ -193,35 +194,24 @@ static int netctrl_connected_count(void)
  * @param dev device
  * @return 0 on success, error code otherwise
  */
-static int vif_wake(struct net_device *dev){
-    int err = 0;
+static int vif_wake(struct net_device *dev)
+{
     struct sk_buff *skb;
-    u32 src_ip;
-    u32 dst_ip = INADDR_BROADCAST;
-    unsigned char dst_hw[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+    u32             src_ip, dst_ip;
+    unsigned char   dst_hw[ETH_ALEN];
 
+    memset(dst_hw, 0xff, ETH_ALEN);
+
+    dst_ip = INADDR_BROADCAST;
     src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
+
     skb = arp_create(ARPOP_REQUEST, ETH_P_ARP,
                      dst_ip, dev, src_ip,
                      dst_hw, dev->dev_addr, NULL);
-    if(skb == NULL){
-        err = -ENOMEM;
-        goto exit;
-    }
-    err = dev_queue_xmit(skb);
-  exit:
-    return err;
-}
+    if ( skb == NULL )
+        return -ENOMEM;
 
-static inline struct sk_buff *alloc_skb_page(void)
-{
-    struct sk_buff *skb;
-    skb = __dev_alloc_skb((PAGE_SIZE/2)+1, GFP_ATOMIC|__GFP_NOWARN);
-#if 0
-    if ( skb && unlikely(((unsigned long)skb->head & (PAGE_SIZE-1)) != 0) )
-        panic("alloc_skb needs to provide us page-aligned buffers.");
-#endif
-    return skb;
+    return dev_queue_xmit(skb);
 }
 
 static int network_open(struct net_device *dev)
index 129c68f4197192b197de616c585f072a85e3ed42..ce9a1c6cf39a982bc2ad5071e67648d857b26baf 100644 (file)
 #ifndef __ASSEMBLY__
 
 #include <linux/config.h>
+#include <linux/string.h>
 #include <linux/types.h>
 #include <asm/hypervisor-ifs/hypervisor-if.h>
 
+#ifdef CONFIG_XEN_SCRUB_PAGES
+#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
+#else
+#define scrub_pages(_p,_n) ((void)0)
+#endif
+
 #ifdef CONFIG_X86_USE_3DNOW
 
 #include <asm/mmx.h>
index ba4e27dbc537a47b0cc5c296ab4c0cb0a7eff3c8..5f77865c22c61b549280a7a5ccf7d3e0fc833b61 100644 (file)
@@ -936,18 +936,18 @@ static inline void __skb_queue_purge(struct sk_buff_head *list)
  *
  *     %NULL is returned in there is no free memory.
  */
+#ifndef CONFIG_HAVE_ARCH_DEV_ALLOC_SKB
 static inline struct sk_buff *__dev_alloc_skb(unsigned int length,
                                              int gfp_mask)
 {
-       struct sk_buff *skb;
-#ifdef CONFIG_PAGESIZED_SKBS
-       length = max(length, (unsigned int)(PAGE_SIZE - 16));
-#endif
-       skb = alloc_skb(length + 16, gfp_mask);
+       struct sk_buff *skb = alloc_skb(length + 16, gfp_mask);
        if (likely(skb))
                skb_reserve(skb, 16);
        return skb;
 }
+#else
+extern struct sk_buff *__dev_alloc_skb(unsigned int length, int gfp_mask);
+#endif
 
 /**
  *     dev_alloc_skb - allocate an skbuff for sending
index 1d4d476464568aea5e16c4e4740049df4bc3db06..7e793d46079b5b20b9174247c74a7f45e01cbf5b 100644 (file)
@@ -28,6 +28,7 @@
 #include <xen/spinlock.h>
 #include <xen/slab.h>
 #include <xen/irq.h>
+#include <asm/domain_page.h>
 
 extern char opt_badpage[];
 
@@ -427,6 +428,7 @@ void free_domheap_pages(struct pfn_info *pg, int order)
 {
     int            i, drop_dom_ref;
     struct domain *d = pg->u.inuse.domain;
+    void          *p;
 
     if ( unlikely(IS_XEN_HEAP_FRAME(pg)) )
     {
@@ -448,14 +450,22 @@ void free_domheap_pages(struct pfn_info *pg, int order)
 
         for ( i = 0; i < (1 << order); i++ )
         {
-#ifndef NDEBUG
-           if ( pg[i].u.inuse.type_info & PGT_count_mask )
-               printk("ERROR: type count not zero on free %x\n",
-                      pg[i].u.inuse.type_info );
-#endif
+            ASSERT((pg[i].u.inuse.type_info & PGT_count_mask) == 0);
             pg[i].tlbflush_timestamp  = tlbflush_clock;
             pg[i].u.free.cpu_mask     = 1 << d->processor;
             list_del(&pg[i].list);
+
+            /*
+             * Normally we expect a domain to clear pages before freeing them,
+             * if it cares about the secrecy of their contents. However, after
+             * a domain has died we assume responsibility for erasure.
+             */
+            if ( unlikely(test_bit(DF_DYING, &d->flags)) )
+            {
+                p = map_domain_mem(page_to_phys(&pg[i]));
+                clear_page(p);
+                unmap_domain_mem(p);
+            }
         }
 
         d->tot_pages -= 1 << order;